
package SocKet;

import ManagerInfoFile.FileNodeMap;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import ManagerInfoFile.ListChunk;
import ManagerInfoFile.NodeConected;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InterruptedIOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;

public class Client {
    private DatagramSocket dataGramSocket;
    private int port;
    private String address;
    private InetAddress IPAddress;
    private FileNodeMap dsNode;
    private ListChunk listchunk;
    private NodeConected[] DanhSachNodeConnected;
    private int maxLengthData = 64512;
    public Client()
    {
        this.dataGramSocket = null;
        this.port = 0;
        this.address = null;   
        dsNode = new FileNodeMap();
    }
    //doc file torrent chua ten cac chunk
    public void ReadDataTorrent(String urlFileName)
    {
        listchunk = new ListChunk();
        listchunk.ReadFileTorrent(urlFileName);
        DanhSachNodeConnected = new NodeConected[listchunk.GetLength()];
        for(int i=0; i<listchunk.GetLength();i++)
        {
            DanhSachNodeConnected[i] = new NodeConected();
        }
    }
    //doc cac node tu tap tin
    public void ReadDataNode()
    {
        dsNode.ReadNodeMap(dsNode.GetFileName());
        //this.address = dsNode.GetNodeInfo(0).GetIpAddress();
        //this.port = dsNode.GetNodeInfo(0).GetPort();
        
    }
    // ip ket noi duoc
    public Boolean KiemTraIPConected()
    {
        for(int i=0; i<DanhSachNodeConnected.length;i++)
        {
            if(DanhSachNodeConnected[i].GetPort() == 0)
                return false;
        }
        return true;
    }
    // ip da co trong ds co chi phi chua
    public Boolean KiemTraIpTonTai(int index)
    {
        if(DanhSachNodeConnected[index].GetPort() == 0)
            return false;
        return true;
    }
    public void SendBroadCast()
    {
        for(int i=1; i < dsNode.GetLength();i++)
        {
            SendBroadCastToAddress(dsNode.GetNodeInfo(i).GetIpAddress(),dsNode.GetNodeInfo(i).GetPort());
            if(KiemTraIPConected())
                break;
        }
        try {
            Thread.sleep(5000);
        } catch (InterruptedException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        DownLooadFile();
        TongHopCacChunkThanhFile();
    }
    public void TongHopCacChunkThanhFile()
    {
        FileOutputStream fos;
        FileInputStream fis;
        List<byte[]> listDataFull = new ArrayList<byte[]>();
        byte[] dataFile;
        File file;
        if(listchunk.KiemTraFileHoanThanh())
        {
             for(int i=0; i<listchunk.GetLength();i++)
             {                 
                try {
                   file = new File("./Data/Download/"+listchunk.GetChunkinfo(i).GetTenFile());
                   dataFile = new byte[(int) file.length()];
                   fis = new FileInputStream(file);
                   fis.read(dataFile);
                   
                   listDataFull.add(dataFile);
                   
                   fis.close();                   
               }catch (FileNotFoundException ex) {
                   System.out.println("Lỗi, Không Tìm Thấy Đường Dẫn"+ ex.getMessage());
               }catch(IOException io) {
                   System.out.println("Lỗi ghi file "+ io.getMessage());
               }
             }
             try
             {
                fos = new FileOutputStream(new File("./Data/Download/"+listchunk.GetFileName()));

                for(int i=0; i < listDataFull.size();i++)
                {   
                    fos.write(listDataFull.get(i));
                }
                fos.flush();
                fos.close();
                System.out.println("Ghi File Thành Công");
                JOptionPane.showMessageDialog(null, "Tải File Thành Công");

             }catch (FileNotFoundException ex) {
                   System.out.println("Lỗi, Không Tìm Thấy Đường Dẫn"+ ex.getMessage());
             }catch(IOException io) {
                   System.out.println("Lỗi ghi file "+ io.getMessage());
             }
             
        }
        else
        {
             System.out.println("Các Chunk chưa Hoàn Thành");
        }
        
    }
    public void DownLooadFile()
    {
        for(int i=0; i<listchunk.GetLength();i++)
        {
           String str = SendYeuCauTaiFile( DanhSachNodeConnected[i].GetIpAddress(), DanhSachNodeConnected[i].GetPort(),
           listchunk.GetChunkinfo(i).GetTenFile());
           if(str.equals("Finish"))
           {
               listchunk.SetSoLuongFileChunkDownloadThanhCong();
           }
           System.out.println("filename chunk thu "+i+listchunk.GetChunkinfo(i).GetTenFile());
        }
        
    }
    public String SendYeuCauTaiFile(InetAddress IPAddress, int port,String FileName)
    {
        String strKetQua = "Lỗi";
        try {
            dataGramSocket = new DatagramSocket();
            dataGramSocket.setSoTimeout(3000);
            byte[] dataSend ;
            byte[] dataReceiveSize = new byte[1024];
            byte[] dataReceive = new byte[maxLengthData];
            int length =0;
            int dem=0;
            // System.out.println(Integer.toString(listchunk.GetLength()));
            // send 
            dataSend = FileName.getBytes();
            DatagramPacket sendPacket ;
            DatagramPacket receivePacket ;
            sendPacket = new DatagramPacket(dataSend, dataSend.length, IPAddress, port);
            dataGramSocket.send(sendPacket);
            
            System.out.println("Send yeu cau tai file");
            //receive
            receivePacket= new DatagramPacket(dataReceiveSize,0, dataReceiveSize.length);
            // ham nhan datagrampacket 
            dataGramSocket.receive(receivePacket);
            String str = new String(receivePacket.getData());
            
            length = Integer.parseInt(SplitString(str));
            System.out.println("kich thuoc"+length);
            //while()
            List<byte[]> listData = new ArrayList<byte[]>();
            while(true)
            {
                if(dem >= length)
                {
                    System.out.println("Nhận dữ liệu Hoàn Thành"+dem);
                    break;
                }
                // send  yeu cau goi thu i
                String strdem = Integer.toString(dem) +"-";
                dataSend = strdem.getBytes();
                sendPacket = new DatagramPacket(dataSend, dataSend.length, IPAddress, port);
                dataGramSocket.send(sendPacket);
                 System.out.println("client yeu cau"+dem);
                // nhan data
                receivePacket= new DatagramPacket(dataReceive,0, dataReceive.length);
                dataGramSocket.receive(receivePacket);
                String data = new String(receivePacket.getData());
                data = SplitString(data);
                listData.add(data.getBytes());
                dem++;
                
            }
            // check dữ liệu download về đúng ko
           
            FileOutputStream fos;
            FileInputStream fis;
            try {
                fos = new FileOutputStream(new File("./Data/Download/"+FileName));

                for(int i=0; i < listData.size();i++)
                {   
                    fos.write(listData.get(i));
                }
                fos.flush();
                fos.close();
                
                File file = new File("./Data/Download/"+FileName);
                byte[] dataFile = new byte[(int) file.length()];
	        
                fis = new FileInputStream(file);
                fis.read(dataFile);
                fis.close();
                if(CheckDataChunkDownLoad(dataFile,FileName))
                {
                    System.out.println("Kiểm tra dữ liệu tải về thành công");
                    strKetQua = "Finish";
                }
                else
                {
                    System.out.println("Dữ liệu tải về bị lỗi");
                    strKetQua = "Lỗi";
                }
            }catch (FileNotFoundException ex) {
                System.out.println("Lỗi, Không Tìm Thấy Đường Dẫn"+ ex.getMessage());
            }catch(IOException io) {
                System.out.println("Lỗi ghi file "+ io.getMessage());
            }
            
            
            System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>");
            
        }
        catch (InterruptedIOException oe) 
        {
            // thời gian chờ kết, cần kết nối đến ip khác gởi lại socket
            System.out.println("Socket time out, "+oe.getMessage());
            strKetQua = "TimeOut";
        } 
        catch (SocketException ex) {
            System.out.println("Lỗi-Socket "+ex.getMessage());
            strKetQua = "Lỗi";
        } catch(IOException io){
            System.out.println("Lỗi-Socket Send "+io.getMessage());
            strKetQua = "Lỗi";
        } 
        return  strKetQua;
    }
    public void SendBroadCastToAddress(String ipaddress, int port)
    {
        try {
           
            dataGramSocket = new DatagramSocket();
            InetAddress IPAddress =InetAddress.getByName(ipaddress);;
            String strsend = "";
            byte[] dataSend ;
            System.out.println(Integer.toString(listchunk.GetLength()));
            // send 
            strsend = strsend + listchunk.GetLength() + "-";
            dataSend = strsend.getBytes();
            DatagramPacket sendPacket ;
            DatagramPacket receivePacket ;
            sendPacket = new DatagramPacket(dataSend, dataSend.length, IPAddress, port);
            dataGramSocket.send(sendPacket);

            
            for(int i=0; i < listchunk.GetLength();i++)
            {
                strsend = listchunk.GetChunkinfo(i).GetTenFile();
                dataSend = strsend.getBytes();
                sendPacket = new DatagramPacket(dataSend, dataSend.length, IPAddress, port);
                dataGramSocket.send(sendPacket);
                
                byte[] dataReceive = new byte[1024];
                receivePacket= new DatagramPacket(dataReceive,0, dataReceive.length);
         
                dataGramSocket.receive(receivePacket);
                String strReceive = new String(receivePacket.getData());
                String [] str = strReceive.split("-");
                String t1 = new String(str[0]);
                String t2 = new String("YES");
                if(t1.equals(t2))
                { 
                    if(!KiemTraIpTonTai(i))
                    {
                        DanhSachNodeConnected[i].SetInetAddress(receivePacket.getAddress()); 
                        DanhSachNodeConnected[i].SetPort(receivePacket.getPort());
                        System.out.println(">>>>>>>>address" + DanhSachNodeConnected[i].GetIpAddress());
                    }
                    
                }
                System.out.println("Response from server:" +i +"data "+ strReceive);
            }
            dataGramSocket.close();
        } catch(IOException io) {
            System.out.println("Lỗi - Không Khởi Tạo Được Socket "+io.getMessage());
        } 
     
    }
    // cắt ký tự kết thúc ("-": Người dùng quy định) chuỗi khi nhận dc.
    public String SplitString(String str)
    {
        String [] strlist = str.split("-");
        if(strlist.length>0)
        {
            return strlist[0];
        }
        return null;
    }
    // kiem tra du lieu download ve dung ko
    public Boolean CheckDataChunkDownLoad(byte[] data, String fileNameChunk)
    {
        String[] fileName= fileNameChunk.split(".");
        if(SHA1(data).equals(fileName[0]))
	     return true;
        return false;
    }
    // ghi ra chuoi ma hoa SHA1 theo dung luong file
    public String SHA1(byte[] data)
    {
        StringBuffer sb = new StringBuffer();
        try
        {
            MessageDigest mDigest = MessageDigest.getInstance("SHA1");
            byte[] result = mDigest.digest(data);
            for(int i=0; i<result.length;i++)
            {
                sb.append(Integer.toString((result[i] & 0xff) + 0x100, 16).substring(1));
            }
        }
        catch (NoSuchAlgorithmException ex)
        {
            ex.printStackTrace();
        }
        return sb.toString();
    }
}
